/*
 * @Author: 13177709051 3506463075@qq.com
 * @Date: 2024-12-03 16:16:16
 * @LastEditors: 13177709051 3506463075@qq.com
 * @LastEditTime: 2024-12-03 16:50:33
 * @FilePath: /highly-concurrent-server/example/any.cpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
// 通⽤类型any类型的实现：
// 每⼀个Connection对连接进⾏管理，最终都不可避免需要涉及到应⽤层协议的处理，因此在
// Connection中需要设置协议处理的上下⽂来控制处理节奏。但是应⽤层协议千千万，为了降低耦合
// 度，这个协议接收解析上下⽂就不能有明显的协议倾向，它可以是任意协议的上下⽂信息，因此就需
// 要⼀个通⽤的类型来保存各种不同的数据结构。
// 在C语⾔中，通⽤类型可以使⽤void*来管理，但是在C++中，boost库和C++17给我们提供了⼀个通⽤
// 类型any来灵活使⽤，如果考虑增加代码的移植性，尽量减少第三⽅库的依赖，则可以使⽤C++17特性
// 中的any，或者⾃⼰来实现。⽽这个any通⽤类型类的实现其实并不复杂，以下是简单的部分实现。


#include <iostream>
#include <typeinfo>
#include <cassert>
#include <unistd.h>
#include <any>

class Any
{
private:
    class holder
    {
    public:
        virtual ~holder() {}
        virtual const std::type_info& type() = 0;
        virtual holder *clone() = 0;
    };
    template<class T>
    class placeholder : public holder
    {
    public:
        placeholder(const T &val) :_val(val) {}
        // 获取子类对象保存的数据类型
        virtual const std::type_info& type() {return typeid(T);}
        // 针对当前的对象自身, 克隆出一个新的子类对象
        virtual holder *clone() {return new placeholder(_val);}
    public:
        T _val;
    };
    holder *_content;
public:
    Any() :_content(NULL) {}
    template<class T>
    Any(const T &val) :_content(new placeholder<T>(val)) {}
    Any(const Any &other) :_content(other._content ? other._content->clone() : NULL) {}
    ~Any() {delete _content;}

    Any &swap(Any &other)
    {
        std::swap(_content, other._content);
        return *this;
    }

    // 返回子类对象保存的数据的指针
    template<class T>
    T *get()
    {
        // 想要获取的数据类型, 必须和保存的数据类型一致
        assert(typeid(T) == _content->type());
        return &((placeholder<T>*)_content)->_val;
    }
    // 赋值运算符的重载函数
    template<class T>
    Any& operator=(const T &val)
    {
        // 为 val 构造一个临时的通用容器, 然后与当前容器自身进行指针交换, 临时对象释放的时候, 原先保存的数据也就被释放
        Any(val).swap(*this);
        return *this;
    }
    Any& operator=(const Any &other)
    {
        Any(other).swap(*this);
        return *this;
    }
};


class Test{
    public:
        Test() {std::cout << "构造" << std::endl;}
        Test(const Test &t) {std::cout << "拷贝" << std::endl;}
        ~Test() {std::cout << "析构" << std::endl;}
};
int main()
{

    std::any a;
    a = 10;
    int *pi = std::any_cast<int>(&a);
    std::cout << *pi << std::endl;

    a = std::string("hello");
    std::string *ps = std::any_cast<std::string>(&a);
    std::cout << *ps << std::endl;
    /*
    Any a;
    {
        Test t;
        a = t;
    }
    
    a = 10;
    int *pa = a.get<int>();
    std::cout << *pa << std::endl;
    a = std::string("nihao");
    std::string *ps = a.get<std::string>();
    std::cout << *ps << std::endl;
    */
    while(1) sleep(1);
    return 0;
}


// 当你构造一个 Any 对象并传入某个值（例如，整数、字符串等），Any 会使用模板类 placeholder<T> 来封装该值。
// placeholder<T> 是一个模板类，它会将值 val 存储在成员变量 _val 中，并将类型信息封装起来。由于 Any 只持有 holder 类型的指针（_content），它不知道存储的是具体什么类型，只能通过 holder 提供的接口来操作数据。
// 当你复制一个 Any 对象时，拷贝构造函数会调用 clone() 方法来创建一个新的副本。clone() 返回的是一个新的 holder 类型的指针，但这个新指针指向的是一个相同类型的 placeholder<T> 对象。
// 通过 clone()，新的 Any 对象会拥有独立的副本，而不会影响原有的 Any 对象。
// 析构函数会删除 _content 指向的对象。由于 holder 是一个基类指针，它将正确地调用 placeholder<T> 类型的析构函数，从而删除 Any 内部存储的对象。



// 在你提供的代码中，holder 类和 placeholder 类都涉及到了 虚函数。虚函数在 C++ 中的主要作用是支持 多态性。简单来说，虚函数使得你可以通过基类指针或引用来调用派生类的函数。这种机制是 C++ 面向对象编程的一个核心特性。
// 接下来，我们分析一下这段代码中虚函数的作用。
// 1. holder 类中的虚函数
// holder 类定义了两个虚函数：
// virtual ~holder() {}：虚析构函数
// virtual const std::type_info& type() = 0;：纯虚函数
// virtual holder* clone() = 0;：纯虚函数
// 这两个纯虚函数要求所有派生类（如 placeholder）必须提供实现，因此 holder 是一个抽象基类。
// a. virtual ~holder() {} — 虚析构函数
// 虚析构函数的作用是确保在通过基类指针删除派生类对象时，会正确调用派生类的析构函数。如果没有虚析构函数，则当通过基类指针删除派生类对象时，可能导致派生类的析构函数不被调用，从而导致资源泄露或未定义行为。
// b. virtual const std::type_info& type() = 0; — 纯虚函数
// 这是一个 纯虚函数，意味着任何继承自 holder 的类都必须实现该函数。在 holder 类中，type() 的作用是获取存储数据的类型信息。
// type() 的作用：在 Any 类的上下文中，我们可能不清楚存储的数据类型是什么，因此我们需要一种机制来动态地获取这些数据的类型。type() 方法返回一个 const std::type_info&，该对象包含了存储数据的类型信息。
// 为什么是纯虚函数：由于 holder 是一个抽象基类，它并不知道具体存储的是什么类型的数据。因此，type() 函数必须在派生类中实现，每个派生类根据其存储的数据类型来返回正确的类型信息。
// c. virtual holder* clone() = 0; — 纯虚函数
// clone() 是另一个纯虚函数，要求所有派生类都实现它。它的作用是 克隆 当前对象，即创建一个当前对象的副本。
// 克隆的用途：在 Any 类中，如果你需要复制存储在 holder 中的对象，clone() 就会被调用。由于 Any 类在拷贝时会通过基类指针进行复制，虚函数确保每个派生类都能根据自己的类型正确地克隆自身。
// 2. placeholder 类中的虚函数实现
// placeholder 类是 holder 的派生类，实现了 holder 中的虚函数。这里有两个重要的实现：
// a. virtual const std::type_info& type() { return typeid(T); }
// 这个方法在 placeholder 中实现，返回了存储在 placeholder 对象中的数据的类型信息。
// typeid(T)：这是一个 C++ 的类型信息工具，返回编译时类型 T 的 std::type_info 对象。T 是 placeholder 的模板参数，它代表了 placeholder 中存储的具体数据类型。
// 每个 placeholder 对象都能返回其保存的数据的类型信息，因此通过这个虚函数，我们可以动态地知道存储的数据是什么类型。
// b. virtual holder* clone() { return new placeholder(_val); }
// 这个方法实现了克隆功能，它返回一个新的 placeholder 对象，该对象与当前对象具有相同的值（通过 _val 进行复制）。
// new placeholder(_val)：它会通过复制构造函数创建一个新的 placeholder 对象，该对象存储的值与当前对象 _val 相同。由于 clone() 是虚函数，当通过基类指针调用时，派生类的 clone() 函数会被调用，从而能够克隆出正确的类型。
// 3. 虚函数的作用总结
// 虚函数的主要作用是支持 多态，它允许我们通过基类指针或引用调用派生类中重写的函数。
// 多态性：在这段代码中，通过基类指针 holder* 可以操作不同类型的派生类对象，而不会在编译时知道具体的类型。例如，通过 Any 类中的 holder*，你可以存储任何类型的对象，并且可以通过 type() 获取该对象的类型信息，或者通过 clone() 创建对象的副本。
// 运行时动态绑定：通过虚函数机制，当你通过基类指针（如 holder*）调用函数时，实际调用的是派生类中重写的函数。这种机制发生在运行时（动态绑定），而不是编译时。这样，无论你通过哪个派生类实例化的对象调用基类方法，都会调用该派生类版本的方法。